using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Grammars.Core.BottomUp;
using Grammars.Core.TopDown;

namespace Grammars.Core
{
    public static class Parsers
    {
        public static IParser<T> BuildLl<T>(Grammar<T> grammar)
            where T : Node, new()
        {
            return new PredictiveParser<T>(grammar);
        }

        public static IParser<T> BuildLr<T>(Grammar<T> grammar)
            where T : Node, new()
        {
            LrState<T>[] states;
            return BuildLr(grammar, out states);
        }

        public static IParser<T> BuildLr<T>(Grammar<T> grammar, out LrState<T>[] states)
            where T : Node, new()
        {
            var builder = new LrParserBuilder<T>(grammar);
            return new ShiftReduceParser<T>(builder.Build(out states), grammar);
        }

        public static IParser<T> Load<T>(Stream stream)
            where T : Node, new()
        {
            if (stream == null)
                throw new ArgumentNullException("stream");

            var bf = new BinaryFormatter();
            return (IParser<T>)bf.Deserialize(stream);
        }

        public static IParser<T> Load<T>(string path)
            where T : Node, new()
        {
            if (path == null)
                throw new ArgumentNullException("path");

            return Load<T>(new FileStream(path, FileMode.Open, FileAccess.Read));
        }

        public static T ParseString<T>(this IParser<T> parser, string str)
            where T : Node, new()
        {
            return parser.Parse(new TokenStream<T>(new StringReader(str), parser.Grammar));
        }

        public static T Parse<T>(this IParser<T> parser, string path)
            where T : Node, new()
        {
            return parser.Parse(new TokenStream<T>(path, parser.Grammar));
        }

        public static T Parse<T>(this IParser<T> parser, Stream stream) 
            where T : Node, new()
        {
            return parser.Parse(new TokenStream<T>(stream, parser.Grammar));
        }
    }
}